package com.migrate.module.config;

import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.migrate.module.domain.ScrollDbConfig;
import com.migrate.module.domain.ScrollDomain;
import com.migrate.module.domain.ScrollShardConfig;
import com.migrate.module.service.MigrateConfigService;
import com.migrate.module.service.MigrateService;
import com.migrate.module.sharding.DataSourceConfig;
import com.migrate.module.sharding.MigrateDataSourceConfig;
import com.migrate.module.sharding.TableRuleConfig;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.session.SqlSession;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.SqlSessionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.sql.DataSource;
import java.sql.Connection;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
@Component
public class ScrollDataSourceConfig extends AbstractDataSourceConfig {

    /**
     * 存储需要进行数据迁移的数据源对象
     */
    private Map<String, SqlSessionTemplate> dataSourceMap = new HashMap<>();

    @Autowired
    private MigrateConfigService migrateConfigService;

    private static final String driverClassName = "com.mysql.cj.jdbc.Driver";

    private static final String split = "&";

    /**
     * 初始化加载目前需要进行数据迁移的相关配置
     */
    @PostConstruct
    public void initMigrateDateSource() throws Exception{
        // 获取所有的需要迁移的配置 系统域对象
        List<ScrollDomain> scrollDomainList = migrateConfigService.queryScrollDomainList();

        // 按系统业务，加载当前的数据源信息
        for (ScrollDomain scrollDomain:scrollDomainList){
            // 当前系统对应的数据源信息
            List<ScrollDbConfig> scrollDbConfigList = migrateConfigService.queryScrollDbConfigList(scrollDomain.getId());
            //当前数据源对应的分区策略
            List<ScrollShardConfig> scrollShardConfigs = migrateConfigService.queryScrollShardConfigList(scrollDomain.getId());
            MigrateDataSourceConfig migrateDataSourceConfig = new MigrateDataSourceConfig();
            migrateDataSourceConfig.setDataSources(buildDataSourceConfig(scrollDbConfigList));
            migrateDataSourceConfig.setTableRules(buildTableRuleConfig(scrollShardConfigs));
            migrateDataSourceConfig.setSqlshow(scrollDomain.getSqlshow() == 0 ? false:true);
            migrateDataSourceConfig.setTableNum(scrollDomain.getTableNum());
            // 加载数据源
            DataSource dataSource = buildDataSource(migrateDataSourceConfig);
            log.info("当前正在加载:【"+scrollDomain.getDomain()+"】的数据源："+"加载数据源数量："+scrollDbConfigList.size());
            SqlSessionFactoryBean sqlSessionFactory = new SqlSessionFactoryBean();
            sqlSessionFactory.setDataSource(dataSource);

            // 缓存对应的数据源信息
            dataSourceMap.put(scrollDomain.getDomain()+split+scrollDomain.getDataSourceType(),  new SqlSessionTemplate(sqlSessionFactory.getObject()));
        }
    }

    /**
     * 获取数据源
     * @param domain 渠道系统应用名称
     * @param dataSourceType 数据源类型
     * @return
     */
    public SqlSession getSqlSession(String domain, Integer dataSourceType){
        try {
            SqlSessionTemplate sqlSessionTemplate = dataSourceMap.get(domain + split + dataSourceType);

            return SqlSessionUtils.getSqlSession(sqlSessionTemplate.getSqlSessionFactory(),
                    sqlSessionTemplate.getExecutorType(), sqlSessionTemplate.getPersistenceExceptionTranslator());

        }catch (Exception e){
            log.error("加载数据源对应连接池失败", e);
        }
        return null;
    }
    /**
     * 关闭sqlSession
     * @param session
     */
    public void closeSqlSession(SqlSession session,String domain, Integer dataSourceType) {
        SqlSessionTemplate sqlSessionTemplate = dataSourceMap.get(domain + split + dataSourceType);

        SqlSessionUtils.closeSqlSession(session, sqlSessionTemplate.getSqlSessionFactory());
    }

    /**
     * 将数据配置封装为原始的数据源配置类
     * @param scrollDbConfigList
     * @return
     */
    private List<DataSourceConfig> buildDataSourceConfig(List<ScrollDbConfig> scrollDbConfigList){
        List<DataSourceConfig> dataSourceConfigList = new ArrayList<>();
        // 填充数据源配置
        for (ScrollDbConfig scrollDbConfig:scrollDbConfigList){
            DataSourceConfig dataSourceConfig = new DataSourceConfig();
            dataSourceConfig.setDriverClassName(driverClassName);
            dataSourceConfig.setUrl(scrollDbConfig.getJdbcUrl());
            dataSourceConfig.setPassword(scrollDbConfig.getJdbcPassword());
            dataSourceConfig.setUsername(scrollDbConfig.getJdbcUserName());
            dataSourceConfigList.add(dataSourceConfig);
        }
        return dataSourceConfigList;
    }

    /**
     * 加载当前数据源对应的分区分表策略
     * @param scrollShardConfigList
     * @return
     */
    private  List<TableRuleConfig> buildTableRuleConfig(List<ScrollShardConfig> scrollShardConfigList){
        List<TableRuleConfig> tableRuleConfigList = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(scrollShardConfigList)){
            for (ScrollShardConfig scrollShardConfig:scrollShardConfigList){
                TableRuleConfig tableRuleConfig = new TableRuleConfig();
                tableRuleConfig.setDbShardingAlgorithm(scrollShardConfig.getDbShardingAlgorithm());
                tableRuleConfig.setDbShardingColumns(scrollShardConfig.getDbShardingColumns());
                tableRuleConfig.setLogicTable(scrollShardConfig.getLogicModel());
                tableRuleConfig.setTableShardingAlgorithm(scrollShardConfig.getTableShardingAlgorithm());
                tableRuleConfig.setTableShardingColumns(scrollShardConfig.getTableShardingColumns());
                tableRuleConfigList.add(tableRuleConfig);
            }
        }
        return tableRuleConfigList;
    }



}
